#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>


#define SERVER_IP      "192.168.231.131"           //ubuntu 本地的ip地址
#define SERVER_PORT    5001                        //ubuntu 本地的端口号

#define BUFFER_SIZE    1024                        //发送、接收缓冲区大小
#define PF_NAME_LEN    100                         //文件路径名称长度


/***建立服务端接收文件***/
/*
1、建立套接字---------socket()
2、绑定本地IP和端口号--bind()
3、监听--------------listen()
4、接收客户端---------accept()
5、和客户端进行间通信--recv()/read(), send()/write()
6、关闭套接字---------close()
*/
int main(int argc, char* argv[])
{
    int socket_fd = 0;

    socket_fd = socket(AF_INET, SOCK_STREAM, 0);        //创建套接字
    if(-1 == socket_fd)
    {
        perror("socket error");
        return -1;
    }

    struct sockaddr_in server_addr;                     //定义一个IPv4结构体变量，初始化自己的（服务端）的ip地址、端口号
    server_addr.sin_family = AF_INET;                   //IPv4
    server_addr.sin_addr.s_addr = inet_addr(SERVER_IP); //ip地址：本地ip---->网络ip
    server_addr.sin_port = htons(SERVER_PORT);          //端口号：本地端口号---->网络端口号

    int ret = 0;                                        //绑定本地的ip地址和端口号
    ret = bind(socket_fd, (const struct sockaddr *)&server_addr, sizeof(struct sockaddr_in));
    if(-1 == ret)
    {
        perror("bind error");
        return -1;
    }

    char *host_ip = inet_ntoa(server_addr.sin_addr);    //ip地址：网络ip---->本地ip
    uint16_t host_port = ntohs(server_addr.sin_port);   //端口号：网络端口号---->本地端口号
    printf("Successfully bind to local: [%s][%d]\n", host_ip, host_port);

    ret = listen(socket_fd, 20);                        //监听
    if(-1 == ret)
    {
        perror("listen error");
        return -1;
    }
    printf("listening......\n");

    int client_fd = 0;
    struct sockaddr_in client_addr = { 0 };                 //定义一个IPv4结构体变量，存储客户端的ip地址、端口号
    socklen_t client_addr_len = sizeof(struct sockaddr_in);
    client_fd = accept(socket_fd, (struct sockaddr*)&client_addr, &client_addr_len);       //阻塞等待新的客户端连接
    if(-1 == client_fd)
    {
        perror("accept error");
        return -1;
    }

    char *client_ip = inet_ntoa(client_addr.sin_addr);      //ip地址：网络ip---->本地ip
    uint16_t client_port = ntohs(client_addr.sin_port);     //端口号：网络端口号---->本地端口号

    printf("The client is successfully connected: [%s][%d]\n", client_ip, client_port);

    char buf[BUFFER_SIZE] = { 0 };

                                                                //接收客户端发送的文件
    char file_name1[PF_NAME_LEN] = { 0 };
    char file_name2[PF_NAME_LEN] = { 0 };
    char file_name3[PF_NAME_LEN] = { 0 };

    int r_file_fd = 0;
    ssize_t recv_size = 0;
    int buf_len = 0;
    int file_size = 0;

    memset(buf, 0, sizeof(buf));
    recv_size = recv(client_fd, buf, sizeof(buf), 0);               //接收文件的路径
    if(-1 == recv_size)
    {
        perror("recv error");
        return -1;
    }
    else if(0 == recv_size)
    {
        printf("client disconnected.\n");
        return -1;
    }

    strcpy(file_name1, buf);

    memset(buf, 0, sizeof(buf));
    strcpy(buf, "received file successfully.\n");
    printf("%s", buf);
    buf_len = strlen(buf) + 1;
    ret = send(client_fd, buf, buf_len, 0);                         //应答客户端已成功接收文件路径
    if(ret < buf_len)
    {
        perror("answer failed");
        return -1;
    }

    if(NULL != strchr(file_name1, '/'))                              //如果文件路径是绝对路径，需要去掉带‘/’的路径
    {                                                                //即把接收到的文件保存到当前路径下
        strcpy(file_name2, strchr(file_name1, '/'));

        for(int i = 1; '\0' != file_name2[i]; i++)
        {
            file_name3[i - 1] = file_name2[i];
            file_name3[i] = '\0';
        }
    }
    else
    {
        strcpy(file_name3, file_name1);
    }

    r_file_fd = open(file_name3, O_CREAT | O_RDWR, 0777);                 //创建新文件接收客户端发送的文件数据
    if(-1 == r_file_fd)
    {
        perror("creat file received from client failed");
        return -1;
    }
    printf("successfully created file %s, start accepting data.\n", file_name3);


    while(true)
    {
        memset(buf, 0, sizeof(buf));
        recv_size = recv(client_fd, buf, sizeof(buf), 0);                          //接收文件的数据
        if(-1 == recv_size)
        {
            perror("recv error");
            return -1;
        }
        else if(0 == recv_size)
        {
            printf("client disconnected or receive finished.\n");
            break;
        }

        ret = write(r_file_fd, buf, recv_size);                                   //将接收的数据写入到新建的文件中
        if(ret < recv_size)
        {
            perror("write failed");
            return -1;
        }

        file_size += recv_size;
        printf("had recieved %d bytes data.\n", file_size);                      //显示接收数据的进度
    }

    ret = close(r_file_fd);
    if(-1 == ret)
    {
        perror("close file created failed");
        return -1;
    }    

    ret = close(socket_fd);
    if(-1 == ret)
    {
        perror("close error");
        return -1;
    }
    

    return 0;
}
